using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using AspNet.Security.OAuth.Validation;
using IdentityServer4;
using IdentityServer4.AccessTokenValidation;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;

namespace ApiServer
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
            services.AddControllers();
            //services.AddAuthorization();//发现这行可以不用, 在app.UseAuthentication();是必需的
            var id4Setting_Authority = "http://localhost:5000";


            services.AddAuthentication(options =>
                {
                    options.DefaultAuthenticateScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
                    //options.DefaultChallengeScheme = "oidc";
                })
                .AddIdentityServerAuthentication("IdentityServerAccessToken", options =>
                {
                    options.Authority = id4Setting_Authority;//在升级net6, 报错 https://stackoverflow.com/questions/69978649/migration-to-net6/69999972,  我的解决方法是 IdentityModel.AspNetCore.OAuth2Introspection  降级到 5.1.0
                    options.RequireHttpsMetadata = false;
                    options.ApiName = "api1";
                    //options.ApiSecret = "secret";
                    options.LegacyAudienceValidation = true;//IDX10206: Unable to validate audience. The 'audiences' parameter is empty. //https://stackoverflow.com/questions/62645604/asp-net-core-3-0-identity-server-4-4-0-0-securitytokeninvalidaudienceexception

                });


            //services
            //    .AddAuthentication(options =>
            //{
            //    options.DefaultScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
            //    //options.DefaultChallengeScheme = nameof(ResponseAuthenticationHandler); //401
            //    //options.DefaultForbidScheme = nameof(ResponseAuthenticationHandler);    //403
            //})

            ////.AddIdentityServerAuthentication(options =>
            ////{
            ////    //认证方案写法2 : Ids4认证服务自己提供的一个处理程序方案 (要添加额外包)
            ////    //<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="2.7.0" />
            ////    //Ids4自己封装的类库，给出的理由是这样的：
            ////    //support for both JWTs and reference tokens
            ////    //extensible caching for reference tokens
            ////    //unified configuration model
            ////    //scope validation
            ////    //简单单翻译下，使用这种方案，可以同时支持JWT和referencetoken的两个方案，还针对后者做了缓存，scope验证，统一配置模型等等。
            ////    //后来官方好像也发现了这个情况，既然要使用微软的，就不在api资源服务器里引用了，所以GitHub仓库已经归档了
            ////    //官方也已经取消了上边的那种方案，统一使用AddJwtBearer方法了, 好处如下:
            ////    //1、可以和普通的jwt认证统一，因为之前是jwt用AddJwtBearer，ids4用的 AddIdentityServerAuthentication。
            ////    //2、可以取消Api资源服务中对Ids4的引入，比如那个nuget包
            ////})

            //.AddJwtBearer(options =>
            //{
            //    //认证方案写法1 : 基于AspNetCore服务,  这是微软官方提供的支持JWT的认证组件，不用额外安装 Nuget 包。
            //    //JWT 的话还是推荐直接使用 AddJwtBearer ，
            //    options.Authority = "http://localhost:5000";    // base-address of your identityserver
            //    options.RequireHttpsMetadata = false;
            //    // if you are using API resources, you can specify the name here
            //    options.Audience = "api1";
            //    // IdentityServer emits a typ header by default, recommended extra check
            //    //options.TokenValidationParameters.ValidTypes = new[] { "at+jwt" };
            //})
            //.AddScheme<AuthenticationSchemeOptions, ResponseAuthenticationHandler>(nameof(ResponseAuthenticationHandler), o => { 
            //})
            ////// reference tokens
            ////.AddOAuth2Introspection(options =>
            ////{
            ////    //https://www.cnblogs.com/stulzq/p/13095412.html
            ////    //https://mp.weixin.qq.com/s/Is_odHFLp0wS3PXGvfwHWA
            ////    options.Authority = "http://localhost:5000";
            ////    //options.ClientId = "resource1";
            ////    //options.ClientSecret = "secret";
            ////});

            ////如果当前IdentityServer不提供身份认证服务，还可以添加其他身份认证服  
            ////.AddOpenIdConnect("oidc", options =>
            ////{
            ////    //options.SignInScheme = "Cookies";
            ////    //options.Authority = "http://localhost:5000";
            ////    //options.RequireHttpsMetadata = false;
            ////    //options.ClientId = "mvc";
            ////    //options.SaveTokens = true;

            ////    //options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
            ////    //options.SignOutScheme = IdentityServerConstants.SignoutScheme;
            ////    //options.Authority = "https://demo.identityserver.io/";
            ////    //options.ClientId = "implicit";
            ////    //options.TokenValidationParameters = new TokenValidationParameters
            ////    //{
            ////    //    NameClaimType = "name",
            ////    //    RoleClaimType = "role"
            ////    //};
            ////})
            //;

            //自定义授权策略的规则,
            services.AddAuthorization(options =>
            {
                //todo: 不能自定义返回值,
                options.AddPolicy("eMailPolicy",
                    policyBuilder => policyBuilder
                        .RequireAssertion(context =>
                        {
                            var haveQQEmail = false;

                            var allClaim = context.User.Claims.ToList();
                            var obj = (from c in context.User.Claims select new { c.Type, c.Value }).ToList();

                            if (context.User.HasClaim(c => c.Type == "client_eMail"))
                            {
                                var claim = context.User.Claims.First(c => c.Type.Equals("client_eMail"));
                                if (claim.Value.EndsWith("@qq.com"))
                                {
                                    haveQQEmail = true;
                                }
                            }
                            return haveQQEmail;
                        }
                    )
                );
            });

            ////JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

            ////services.AddAuthentication(options =>
            ////    {
            ////        options.DefaultScheme = "Cookies";
            ////        options.DefaultChallengeScheme = "oidc";
            ////    })
            ////    .AddCookie("Cookies")
            ////    



        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseAuthentication();//添加认证中间件到Pipeline

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}
